#include "FT4222.h"

namespace FT4222 {
	FTBase::FTBase():ftHandle(NULL)
	{
		
	}

	FTBase::~FTBase()
	{
		if (ftHandle != NULL) {
			FT4222_UnInitialize(ftHandle);
			FT_Close(ftHandle);
			ftHandle = NULL;
		}
	}

	Ft_STATUS FTBase::Ft_CreateDeviceInfoList(uint32% lpdwNumDevs)
	{
		DWORD tempNumDevs = 0;
		FT_STATUS ftStatus = FT_CreateDeviceInfoList(&tempNumDevs);
		lpdwNumDevs = tempNumDevs;
		return (Ft_STATUS)(ftStatus);
	}

	Ft_STATUS FTBase::Ft_GetDeviceInfoDetail(uint32 dwIndex, uint32% lpdwFlags, Ft_DEVICE% lpdwType, uint32% lpdwID, uint32% lpdwLocId, System::String^% serialNumber, System::String^% description)
	{
		FT_HANDLE ftHandle = NULL;
		DWORD flags;
		DWORD type;
		DWORD id;
		DWORD locId;

		char szSerialNumber[16]{};
		char szDescription[64]{};

		FT_STATUS ftStatus = FT_GetDeviceInfoDetail(
			dwIndex,
			&flags,
			&type,
			&id,
			&locId,
			szSerialNumber,
			szDescription,
			&ftHandle
		);
		lpdwFlags = flags;
		lpdwType = (Ft_DEVICE)type;
		lpdwID = id;
		lpdwLocId = locId;
		serialNumber = gcnew System::String(szSerialNumber);
		description = gcnew System::String(szDescription);

		return (Ft_STATUS)(ftStatus);
	}

	Ft_STATUS FTBase::Ft_OpenEx(System::IntPtr pArg1, Ft_OpenFlag flags)
	{
		pin_ptr<FT_HANDLE> pVariable = &ftHandle;
		FT_STATUS ftStatus = FT_OpenEx(pArg1.ToPointer(), (uint32)flags, pVariable);
		return (Ft_STATUS)(ftStatus);
	}

	Ft_STATUS FTBase::Ft_OpenEx(uint32 locId)
	{
		pin_ptr<FT_HANDLE> pVariable = &ftHandle;
		uintptr_t locIdPtr = static_cast<uintptr_t>(locId);
		FT_STATUS ftStatus = FT_OpenEx(reinterpret_cast<PVOID>(locIdPtr), (uint32)Ft_OpenFlag::Ft_OPEN_BY_LOCATION, pVariable);
		return (Ft_STATUS)(ftStatus);
	}

	Ft_STATUS FTBase::Ft_OpenEx(System::String^ serialNumber)
	{
		pin_ptr<FT_HANDLE> pVariable = &ftHandle;
		System::IntPtr serialNumberPtr = System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(serialNumber);
		FT_STATUS ftStatus = FT_OpenEx((PVOID)serialNumberPtr, (uint32)Ft_OpenFlag::Ft_OPEN_BY_SERIAL_NUMBER, pVariable);
		return (Ft_STATUS)(ftStatus);
	}

	Ft_STATUS FTBase::Ft_Close()
	{
		FT_STATUS ftStatus = FT_Close(ftHandle);
		if (ftStatus == FT_OK) {
			ftHandle = NULL;
		}

		return  (Ft_STATUS)(ftStatus);
	}

	bool FTBase::Ft_IsOpen()
	{
		return ftHandle != NULL;
	}

	Ft4222_STATUS FTBase::Ft4222_UnInitialize()
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		FT4222_STATUS ftStatus = FT4222_UnInitialize(ftHandle);
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS FTBase::Ft4222_SetClock(Ft4222_ClockRate clk)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		FT4222_ClockRate ftClock = (FT4222_ClockRate)(clk);
		return (Ft4222_STATUS)(FT4222_SetClock(ftHandle, ftClock));
	}

	Ft4222_STATUS FTBase::Ft4222_GetClock(Ft4222_ClockRate% clk)
	{
		if (ftHandle == NULL) {
			clk = Ft4222_ClockRate::SYS_CLK_60;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		FT4222_ClockRate ftClk = FT4222_ClockRate::SYS_CLK_60;
		FT4222_STATUS ftStatus = FT4222_GetClock(ftHandle,&ftClk);
		clk = (Ft4222_ClockRate)ftClk;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS FTBase::Ft4222_SetWakeUpInterrupt(bool enable)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		int intEnable = enable ? 1 : 0;
		return (Ft4222_STATUS)(FT4222_SetWakeUpInterrupt(ftHandle, intEnable));
	}

	Ft4222_STATUS FTBase::Ft4222_SetInterruptTrigger(Gpio_Trigger trigger)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		GPIO_Trigger ftTrigger = (GPIO_Trigger)(trigger);
		return (Ft4222_STATUS)(FT4222_SetInterruptTrigger(ftHandle, ftTrigger));
	}

	Ft4222_STATUS FTBase::Ft4222_SetSuspendOut(bool enable)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		int intEnable = enable ? 1 : 0;
		return (Ft4222_STATUS)(FT4222_SetSuspendOut(ftHandle, intEnable));
	}

	Ft4222_STATUS FTBase::Ft4222_GetMaxTransferSize(uint16% pMaxSize)
	{
		if (ftHandle == NULL) {
			pMaxSize = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_GetMaxTransferSize(ftHandle, &size);
		pMaxSize = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS FTBase::Ft4222_SetEventNotification(uint32 mask, System::IntPtr param)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_SetEventNotification(ftHandle, mask, param.ToPointer()));
	}

	Ft4222_STATUS FTBase::Ft4222_GetVersion(Ft4222_Version% pVersion)
	{
		FT4222_Version version = {0,0};
		if (ftHandle == NULL) {
			pVersion.chipVersion = version.chipVersion;
			pVersion.dllVersion = version.dllVersion;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		FT4222_STATUS ftStatus = FT4222_GetVersion(ftHandle, &version);
		pVersion.chipVersion = version.chipVersion;
		pVersion.dllVersion = version.dllVersion;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS FTBase::Ft4222_GetChipMode(byte% pChipMode)
	{
		uint8 mode = 0;
		if (ftHandle == NULL) {
			pChipMode = mode;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		FT4222_STATUS ftStatus = FT4222_GetChipMode(ftHandle, &mode);
		pChipMode = mode;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS FTBase::Ft4222_ChipReset()
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_ChipReset(ftHandle));
	}

	SPI::SPI()
	{

	}

	inline SPI::~SPI()
	{
		//if (ftHandle != NULL) {

		//}
	}

	Ft4222_STATUS SPI::Ft4222_SPIMaster_Init(Ft4222_SPIMode ioLine, Ft4222_SPIClock clock, Ft4222_SPICPOL cpol, Ft4222_SPICPHA cpha, Ft4222_SpiSsoMap ssoMap)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_SPIMaster_Init(ftHandle,
			FT4222_SPIMode(ioLine),
			FT4222_SPIClock(clock),
			FT4222_SPICPOL(cpol),
			FT4222_SPICPHA(cpha), (uint8)ssoMap));
	}

	Ft4222_STATUS SPI::Ft4222_SPIMaster_SetMode(Ft4222_SPICPOL cpol, Ft4222_SPICPHA cpha)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_SPIMaster_SetMode(ftHandle,(FT4222_SPICPOL)cpol,(FT4222_SPICPHA)cpha));
	}

	Ft4222_STATUS SPI::Ft4222_SPIMaster_SetCS(Spi_ChipSelect cs)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_SPIMaster_SetCS(ftHandle, (SPI_ChipSelect)cs));
	}

	Ft4222_STATUS SPI::Ft4222_SPIMaster_SetLines(Ft4222_SPIMode spiMode)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_SPIMaster_SetLines(ftHandle, (FT4222_SPIMode)spiMode));
	}

	Ft4222_STATUS SPI::Ft4222_SPIMaster_SingleRead(array<byte>^ buffer, uint16 bufferSize, uint16% sizeOfRead, bool isEndTransaction)
	{
		if (ftHandle == NULL) {
			sizeOfRead = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<byte> bufferPtr = &buffer[0];
		uint16 sizeOfReadValue = 0;
		uint32 isEnd = isEndTransaction ? 1 : 0;
		FT4222_STATUS ftStatus = FT4222_SPIMaster_SingleRead(ftHandle, bufferPtr, bufferSize,&sizeOfReadValue, isEnd);
		sizeOfRead = sizeOfReadValue;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS SPI::Ft4222_SPIMaster_SingleWrite(array<byte>^ buffer, uint16 bufferSize, uint16% sizeTransferred, bool isEndTransaction)
	{
		if (ftHandle == NULL) {
			sizeTransferred = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}

		pin_ptr<byte> bufferPtr = &buffer[0];
		uint16 sizeOfWriteValue = 0;
		uint32 isEnd = isEndTransaction ? 1 : 0;
		FT4222_STATUS ftStatus = FT4222_SPIMaster_SingleWrite(ftHandle, bufferPtr, bufferSize, &sizeOfWriteValue, isEnd);
		sizeTransferred = sizeOfWriteValue;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS SPI::Ft4222_SPIMaster_SingleReadWrite(array<byte>^ readBuffer, array<byte>^ writeBuffer, uint16 bufferSize, uint16% sizeTransferred, bool isEndTransaction)
	{
		if (ftHandle == NULL) {
			sizeTransferred = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<byte> readBufferPtr = &readBuffer[0];
		pin_ptr<byte> writeBufferPtr = &writeBuffer[0];
		uint16 sizeOfReadWriteValue = 0;
		uint32 isEnd = isEndTransaction ? 1 : 0;
		FT4222_STATUS ftStatus = FT4222_SPIMaster_SingleReadWrite(ftHandle, readBufferPtr, writeBufferPtr, bufferSize, &sizeOfReadWriteValue, isEnd);
		sizeTransferred = sizeOfReadWriteValue;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS SPI::Ft4222_SPIMaster_MultiReadWrite(array<byte>^ readBuffer, array<byte>^ writeBuffer, uint8 singleWriteBytes, uint16 multiWriteBytes, uint16 multiReadBytes, uint32% sizeOfRead)
	{
		if (ftHandle == NULL) {
			sizeOfRead = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<byte> readBufferPtr = &readBuffer[0];
		pin_ptr<byte> writeBufferPtr = &writeBuffer[0];
		uint32 sizeOfReadValue = 0;
		FT4222_STATUS ftStatus = FT4222_SPIMaster_MultiReadWrite(ftHandle, readBufferPtr, writeBufferPtr, singleWriteBytes, multiWriteBytes, multiReadBytes, &sizeOfReadValue);
		sizeOfRead = sizeOfReadValue;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS SPI::Ft4222_SPISlave_Init()
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_SPISlave_Init(ftHandle));
	}

	Ft4222_STATUS SPI::Ft4222_SPISlave_InitEx(Spi_SlaveProtocol protocolOpt)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_SPISlave_InitEx(ftHandle,(SPI_SlaveProtocol)protocolOpt));
	}

	Ft4222_STATUS SPI::Ft4222_SPISlave_SetMode(Ft4222_SPICPOL cpol, Ft4222_SPICPHA cpha)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_SPISlave_SetMode(ftHandle, (FT4222_SPICPOL)cpol,(FT4222_SPICPHA)cpha));
	}

	Ft4222_STATUS SPI::Ft4222_SPISlave_GetRxStatus(uint16% pRxSize)
	{
		if (ftHandle == NULL) {
			pRxSize = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_SPISlave_GetRxStatus(ftHandle,&size);
		pRxSize = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS SPI::Ft4222_SPISlave_Read(array<byte>^ buffer, uint16 bufferSize, uint16% sizeOfRead)
	{
		if (ftHandle == NULL) {
			sizeOfRead = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<byte> readBufferPtr = &buffer[0];
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_SPISlave_Read(ftHandle, readBufferPtr, bufferSize, &size);
		sizeOfRead = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS SPI::Ft4222_SPISlave_Write(array<byte>^ buffer, uint16 bufferSize, uint16% sizeTransferred)
	{
		if (ftHandle == NULL) {
			sizeTransferred = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<byte> writeBufferPtr = &buffer[0];
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_SPISlave_Write(ftHandle, writeBufferPtr, bufferSize, &size);
		sizeTransferred = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS SPI::Ft4222_SPI_Reset()
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_SPI_Reset(ftHandle));
	}

	Ft4222_STATUS SPI::Ft4222_SPI_ResetTransaction(byte spiIdx)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_SPI_ResetTransaction(ftHandle, spiIdx));
	}

	Ft4222_STATUS SPI::Ft4222_SPI_SetDrivingStrength(Spi_DrivingStrength clkStrength, Spi_DrivingStrength ioStrength, Spi_DrivingStrength ssoStrength)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_SPI_SetDrivingStrength(ftHandle,(SPI_DrivingStrength)clkStrength, (SPI_DrivingStrength)ioStrength, (SPI_DrivingStrength)ssoStrength));
	}

	Ft4222_STATUS SPI::SpiClockToSystemClock(Ft4222_SPITransferClock trClock, Ft4222_ClockRate% sysClock, Ft4222_SPIClock% spiDiv)
	{
		Ft4222_STATUS ftStatus = Ft4222_STATUS::FT4222_OK;
		switch (trClock) {
		case Ft4222_SPITransferClock::SPI234_37KHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_60; spiDiv = Ft4222_SPIClock::CLK_DIV_256; break;
		case Ft4222_SPITransferClock::SPI312_5KHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_80; spiDiv = Ft4222_SPIClock::CLK_DIV_256; break;
		case Ft4222_SPITransferClock::SPI375KHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_24; spiDiv = Ft4222_SPIClock::CLK_DIV_64; break;
		case Ft4222_SPITransferClock::SPI468_75KHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_60; spiDiv = Ft4222_SPIClock::CLK_DIV_128; break;
		case Ft4222_SPITransferClock::SPI625KHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_80; spiDiv = Ft4222_SPIClock::CLK_DIV_128; break;
		case Ft4222_SPITransferClock::SPI750KHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_24; spiDiv = Ft4222_SPIClock::CLK_DIV_32; break;
		case Ft4222_SPITransferClock::SPI937_5KHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_60; spiDiv = Ft4222_SPIClock::CLK_DIV_64; break;
		case Ft4222_SPITransferClock::SPI1_25MHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_80; spiDiv = Ft4222_SPIClock::CLK_DIV_64; break;
		case Ft4222_SPITransferClock::SPI1_5MHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_24; spiDiv = Ft4222_SPIClock::CLK_DIV_16; break;
		case Ft4222_SPITransferClock::SPI1_875MHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_60; spiDiv = Ft4222_SPIClock::CLK_DIV_32; break;
		case Ft4222_SPITransferClock::SPI2_5MHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_80; spiDiv = Ft4222_SPIClock::CLK_DIV_32; break;
		case Ft4222_SPITransferClock::SPI3MHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_24; spiDiv = Ft4222_SPIClock::CLK_DIV_8; break;
		case Ft4222_SPITransferClock::SPI3_75MHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_60; spiDiv = Ft4222_SPIClock::CLK_DIV_16; break;
		case Ft4222_SPITransferClock::SPI6MHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_24; spiDiv = Ft4222_SPIClock::CLK_DIV_4; break;
		case Ft4222_SPITransferClock::SPI10MHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_80; spiDiv = Ft4222_SPIClock::CLK_DIV_8; break;
		case Ft4222_SPITransferClock::SPI20MHz:
			sysClock = Ft4222_ClockRate::SYS_CLK_80; spiDiv = Ft4222_SPIClock::CLK_DIV_4; break;
		default:
			sysClock = Ft4222_ClockRate::SYS_CLK_60; spiDiv = Ft4222_SPIClock::CLK_DIV_32;
			ftStatus = Ft4222_STATUS::FT4222_INVALID_ARGS; break;
		}
		return ftStatus;
	}






	I2C::I2C()
	{
		
	}

	I2C::~I2C()
	{
		
	}

	Ft4222_STATUS I2C::Ft4222_I2CMaster_Init(uint32 kbps)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_I2CMaster_Init(ftHandle, kbps));
	}

	Ft4222_STATUS I2C::Ft4222_I2CMaster_Read(uint16 deviceAddress, array<byte>^ buffer, uint16 bufferSize, uint16% sizeTransferred)
	{
		if (ftHandle == NULL) {
			sizeTransferred = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<byte> readBufferPtr = &buffer[0];
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_I2CMaster_Read(ftHandle, deviceAddress, readBufferPtr, bufferSize, &size);
		sizeTransferred = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS I2C::Ft4222_I2CMaster_Write(uint16 deviceAddress, array<byte>^ buffer, uint16 bufferSize, uint16% sizeTransferred)
	{
		if (ftHandle == NULL) {
			sizeTransferred = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<byte> writeBufferPtr = &buffer[0];
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_I2CMaster_Write(ftHandle, deviceAddress, writeBufferPtr, bufferSize, &size);
		sizeTransferred = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS I2C::Ft4222_I2CMaster_ReadEx(uint16 deviceAddress, uint8 flag, array<byte>^ buffer, uint16 bufferSize, uint16% sizeTransferred)
	{
		if (ftHandle == NULL) {
			sizeTransferred = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<byte> readBufferPtr = &buffer[0];
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_I2CMaster_ReadEx(ftHandle, deviceAddress, flag, readBufferPtr, bufferSize, &size);
		sizeTransferred = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS I2C::Ft4222_I2CMaster_WriteEx(uint16 deviceAddress, uint8 flag, array<byte>^ buffer, uint16 bufferSize, uint16% sizeTransferred)
	{
		if (ftHandle == NULL) {
			sizeTransferred = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<byte> writeBufferPtr = &buffer[0];
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_I2CMaster_WriteEx(ftHandle, deviceAddress, flag, writeBufferPtr, bufferSize, &size);
		sizeTransferred = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS I2C::Ft4222_I2CMaster_Reset()
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_I2CMaster_Reset(ftHandle));
	}

	Ft4222_STATUS I2C::Ft4222_I2CMaster_GetStatus(byte% controllerStatus)
	{
		if (ftHandle == NULL) {
			controllerStatus = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		byte status = 0;
		FT4222_STATUS ftStatus = FT4222_I2CMaster_GetStatus(ftHandle,&status);
		controllerStatus = status;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS I2C::Ft4222_I2CMaster_ResetBus()
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_I2CMaster_ResetBus(ftHandle));
	}

	Ft4222_STATUS I2C::Ft4222_I2CSlave_Init()
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_I2CSlave_Init(ftHandle));
	}

	Ft4222_STATUS I2C::Ft4222_I2CSlave_Reset()
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_I2CSlave_Reset(ftHandle));
	}

	Ft4222_STATUS I2C::Ft4222_I2CSlave_GetAddress(byte% addr)
	{
		if (ftHandle == NULL) {
			addr = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		byte mAddr = 0;
		FT4222_STATUS ftStatus = FT4222_I2CSlave_GetAddress(ftHandle, &mAddr);
		addr = mAddr;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS I2C::Ft4222_I2CSlave_SetAddress(byte addr)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_I2CSlave_SetAddress(ftHandle, addr));
	}

	Ft4222_STATUS I2C::Ft4222_I2CSlave_GetRxStatus(uint16% pRxSize)
	{
		if (ftHandle == NULL) {
			pRxSize = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_I2CSlave_GetRxStatus(ftHandle, &size);
		pRxSize = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS I2C::Ft4222_I2CSlave_Read(array<byte>^ buffer, uint16 bufferSize, uint16% sizeTransferred)
	{
		if (ftHandle == NULL) {
			sizeTransferred = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<byte> readBufferPtr = &buffer[0];
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_I2CSlave_Read(ftHandle, readBufferPtr, bufferSize, &size);
		sizeTransferred = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS I2C::Ft4222_I2CSlave_Write(array<byte>^ buffer, uint16 bufferSize, uint16% sizeTransferred)
	{
		if (ftHandle == NULL) {
			sizeTransferred = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<byte> writeBufferPtr = &buffer[0];
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_I2CSlave_Write(ftHandle, writeBufferPtr, bufferSize, &size);
		sizeTransferred = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS I2C::Ft4222_I2CSlave_SetClockStretch(bool enable)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_I2CSlave_SetClockStretch(ftHandle, enable ? 1 : 0));
	}

	Ft4222_STATUS I2C::Ft4222_I2CSlave_SetRespWord(byte responseWord)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_I2CSlave_SetRespWord(ftHandle, responseWord));
	}

	GPIO::GPIO()
	{
		
	}

	GPIO::~GPIO()
	{
		
	}

	Ft4222_STATUS GPIO::Ft4222_GPIO_Init(array<Gpio_Dir>^ gpioDir_1_2_3_4)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		pin_ptr<Gpio_Dir> gpioDirPtr = &gpioDir_1_2_3_4[0];
		return (Ft4222_STATUS)(FT4222_GPIO_Init(ftHandle, (GPIO_Dir *)gpioDirPtr));
	}

	Ft4222_STATUS GPIO::Ft4222_GPIO_Read(Gpio_Port portNum, bool% high)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		int32 isHigh = 0;
		FT4222_STATUS ftStatus = FT4222_GPIO_Read(ftHandle,(GPIO_Port)portNum, &isHigh);
		high = isHigh != 0;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS GPIO::Ft4222_GPIO_Write(Gpio_Port portNum, bool high)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_GPIO_Write(ftHandle, (GPIO_Port)portNum, high ? 1:0));
	}

	Ft4222_STATUS GPIO::Ft4222_GPIO_SetInputTrigger(Gpio_Port portNum, Gpio_Trigger trigger)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_GPIO_SetInputTrigger(ftHandle, (GPIO_Port)portNum, (GPIO_Trigger)trigger));
	}

	Ft4222_STATUS GPIO::Ft4222_GPIO_GetTriggerStatus(Gpio_Port portNum, uint16% queueSize)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		uint16 size = 0;
		FT4222_STATUS ftStatus = FT4222_GPIO_GetTriggerStatus(ftHandle, (GPIO_Port)portNum, &size);
		queueSize = size;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS GPIO::Ft4222_GPIO_ReadTriggerQueue(Gpio_Port portNum, array<Gpio_Trigger>^ events, uint16 readSize, uint16% sizeofRead)
	{
		if (ftHandle == NULL) {
			sizeofRead = 0;
			return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		}
		pin_ptr<Gpio_Trigger> eventPtr = &events[0];
		uint16 readFinishSize = 0;
		FT4222_STATUS ftStatus = FT4222_GPIO_ReadTriggerQueue(ftHandle, (GPIO_Port)portNum, (GPIO_Trigger*)eventPtr, readSize, &readFinishSize);
		sizeofRead = readFinishSize;
		return (Ft4222_STATUS)(ftStatus);
	}

	Ft4222_STATUS GPIO::Ft4222_GPIO_SetWaveFormMode(bool enable)
	{
		if (ftHandle == NULL) return Ft4222_STATUS::FT4222_INVALID_HANDLE;
		return (Ft4222_STATUS)(FT4222_GPIO_SetWaveFormMode(ftHandle, enable ? 1 : 0));
	}

}


